<?php

namespace XXXX\PlatformBundle\Util;

use XXXX\PlatformBundle\Entity\Base\Course;
use Doctrine\Common\Collections\ArrayCollection;
use XXXX\PlatformBundle\Entity\Base\User;
use XXXX\PlatformBundle\Entity\Base\UserCourse;
use XXXX\PlatformBundle\Entity\Base\UserNotification;

/**
 * Move studets to another course
 *
 * @author Ryszard Ratajczak <rratajczak@xxxx.com.pl>
 */
class CoursesMove
{
    /**
     * EntityManager
     *
     * @var EntityManager $em - entity manager
     */
    private $em;

    /**
     * Set EntityManager
     *
     * @param EntityManager $em - entity manager
     */
    public function __construct($em)
    {
        $this->em = $em;
    }

    /**
     * moveStudentsToAnother
     *
     * @param Course  $sourceCourse - sourceCourse
     * @param Course  $destCourse   - destCourse
     * @param array   $studentsIds  - studentsIds
     * @param boolean $moveGrades   - moveGrades
     *
     * @return array
     */
    public function moveStudentsToAnotherCourse(Course $sourceCourse, Course $destCourse, $studentsIds, $moveGrades = false)
    {
        $userCourseRepository =  $this->em->getRepository('XXXXPlatformBundle:Base\UserCourse');
        $userRepository = $this->em->getRepository('XXXXPlatformBundle:Base\User');

        $sourceCourseId = $sourceCourse->getId();
        $destCourseId = $destCourse->getId();
        $connection = $this->em->getConnection();

        $connection->beginTransaction();

        foreach ($studentsIds as $studentId) {
            $user = $userRepository->findOneById($studentId);
            if (!$user) {
                $connection->rollback();

                return array('bool' => false, 'message' => 'move.errors.students');
            }

            $studentSourceCourse = $userCourseRepository->findOneBy(array('user' => $studentId, 'course' => $sourceCourseId));
            if ($studentSourceCourse) {
                if ($studentSourceCourse instanceof \XXXX\PlatformBundle\Entity\Base\UserCourse) {
                    if ($user->getCurrentCourse() == $studentSourceCourse) {
                        $user->setCurrentCourse(null);
                        $this->em->persist($user);
                    }
                    $this->em->remove($studentSourceCourse);
                }
            } else {
                $connection->rollback();

                return array('bool' => false);
            }

            $studentDestCourse = $userCourseRepository->findOneBy(array('user' => $studentId, 'course' => $destCourseId));
            if ($studentDestCourse) {
                $connection->rollback();

                return array('bool' => false, 'message' => 'move.errors.students');
            } else {
                if ($user instanceof \XXXX\PlatformBundle\Entity\Base\User) {
                    $user->addStudentCourse($destCourse);
                    $this->em->persist($user);
                }
            }
        }

        if ($moveGrades) {
            $this->moveStudentsGradesFromCourse($sourceCourse, $destCourse, $studentsIds);
        }

        if ($studentSourceCourse instanceof \XXXX\PlatformBundle\Entity\Base\UserCourse
                && $user instanceof \XXXX\PlatformBundle\Entity\Base\User) {
            $this->em->flush();
            $connection->commit();
        } else {
            $connection->rollback();
        }

        return array('bool' => true);
    }

    /**
     * moveStudentsGradesFromCourse
     *
     * @param Course $sourceCourse - sourceCourse
     * @param Course $destCourse   - destCourse
     * @param Array  $studentsIds  - studentsIds
     */
    public function moveStudentsGradesFromCourse(Course $sourceCourse, Course $destCourse, $studentsIds)
    {
        $sourceAssignments = $this->em->getRepository('XXXXPlatformBundle:Base\Assignment')->findBy(array('course' => $sourceCourse->getId()));

        foreach ($sourceAssignments as $assignment) {

            // move students
            $userAssignments = $assignment->getUserAssignments();
            $userAssignmentsIds = array();
            foreach ($userAssignments as $userAssignment) {
                $userAssignmentsIds[] = $userAssignment->getUser()->getId();
            }

            // when part of students are moved
            if (array_diff($userAssignmentsIds, $studentsIds)) {
                // create assignments
                $newAssignment = clone $assignment;
                $newAssignment->setCourse($destCourse);

                // new settings
                $settings = $assignment->getAssignmentSettings();
                $newAssignmentSettings = clone $settings;
                $newAssignment->setAssignmentSettings($newAssignmentSettings);

                foreach ($userAssignments as $userAssignment) {
                    if (in_array($userAssignment->getUser()->getId(), $studentsIds)) {
                        $userAssignment->setAssignment($newAssignment);
                        $this->em->persist($userAssignment);
                    }
                }

                $this->em->persist($newAssignment);


            } else {
                // move whole assignment
                $assignment->setCourse($destCourse);
                $this->em->persist($assignment);
            }
        }
    }

    /**
     * removeStudentsFromCourse
     *
     * @param Course $course      - course
     * @param array  $studentsIds - studentsIds
     *
     * @return array
     */
    public function removeStudentsFromCourse(Course $course, Array $studentsIds)
    {
        $userCourseRepository =  $this->em->getRepository('XXXXPlatformBundle:Base\UserCourse');
        $userNotificationRepository =  $this->em->getRepository('XXXXPlatformBundle:Base\UserNotification');
        $userRepository =  $this->em->getRepository('XXXXPlatformBundle:Base\User');
        $eventsRepository = $this->em->getRepository('XXXXPlatformBundle:Base\Event');
        $eventNotificationRepository = $this->em
            ->getRepository('XXXXPlatformBundle:Base\Notifications\EventNotification');

        $courseId = $course->getId();
        $teachersIds = $this->em
            ->getRepository('XXXXPlatformBundle:Base\TeacherCourse')
            ->getTeachersIdsForCourse($courseId);
        $events = $eventsRepository->getEventsForStudentsByTeacherIds($studentsIds, $teachersIds);

        $connection = $this->em->getConnection();

        $connection->beginTransaction();
        $eventsIds = array();

        foreach ($studentsIds as $studentId) {
            $userCourse = $userCourseRepository->findOneBy(array(
                'user' => $studentId,
                'course' => $courseId,
            ));

            $user = $userRepository->findOneById($studentId);
            if ($userCourse) {
                if ($userCourse->getDeleted()) {
                    $connection->rollback();

                    return array('bool' => false, 'message' => 'remove.errors.students');
                } else {

                    foreach ($events as $event) {
                        $event->removeUser($user);
                        $this->em->persist($event);
                        $eventsIds[] = $event->getId();
                    }

                    $userCourse->setDeleted(true);

                    if ($user->getCurrentCourse() && $user->getCurrentCourse()->getId() == $courseId) {
                        $user->setCurrentCourse(null);
                        $this->em->persist($user);
                    }

                    $this->em->persist($userCourse);

                    $userNotifications = $userNotificationRepository->getUserCourseNotifications($courseId, $studentId);
                    $eventNotifications = $eventNotificationRepository
                        ->getGeneralEventNotificationsForUser($studentId, $eventsIds);

                    $notificationUsers =  $this->getUserNotificationByEvent($eventNotifications, $user);

                    $userNotifications = array_merge($userNotifications, $notificationUsers);

                    foreach ($userNotifications as $userNotification) {
                        $userNotification->setHidden(true);
                        $this->em->persist($userNotification);
                    }
                }
            } else {
                $connection->rollback();

                return array('bool' => false);
            }

        }
        $this->em->flush();

        $connection->commit();

        return array('bool' => true);
    }

    /**
     * @param array $eventNotifications - array of eventNotifications
     * @param User  $user               - user object
     *
     * @return array
     */
    protected function getUserNotificationByEvent($eventNotifications, $user)
    {
        $notificationUsers = array();
        foreach ($eventNotifications as $eventNotification) {
            $notificationUsers[] = $eventNotification->getNotificationUsers()
                ->filter(
                    function ($notificationUser) use ($user) {
                        if ($notificationUser->getUser() == $user) {

                            return $notificationUser;
                        }
                    }
                )->first();
        }

        return $notificationUsers;
    }
}
